package com.leo.boot.prop.config;

import org.apache.poi.ss.usermodel.*;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.boot.origin.TextResourceOrigin;
import org.springframework.boot.origin.TextResourceOrigin.Location;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import static java.util.Collections.singletonList;
import static java.util.Collections.unmodifiableMap;
import static java.util.Objects.requireNonNull;

public class ExcelPropertySourceLoader implements PropertySourceLoader {

    @Override
    public String[] getFileExtensions() {
        return new String[]{"xls", "xlsx"};
    }

    @Override
    public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
        Map<String, OriginTrackedValue> properties = new LinkedHashMap<>();
        try (Workbook sheets = WorkbookFactory.create(resource.getFile().getCanonicalFile(), null, true)) {
            DataFormatter dataFormatter = new DataFormatter();
            Sheet sheet = sheets.getSheetAt(0);
            List<String> header = rowToList(sheet.getRow(0), dataFormatter);

            String keyPrefix = getPrefix(resource);
            String keyFormatter = keyPrefix + "[%s].%s";

            for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) {
                Row row = sheet.getRow(rowNum);
                for (int columnNum = 0; columnNum < header.size(); columnNum++) {
                    Cell cell = row.getCell(columnNum);
                    String key = String.format(keyFormatter, rowNum - 1, header.get(columnNum));

                    Origin origin = new TextResourceOrigin(resource, new Location(rowNum, columnNum));
                    OriginTrackedValue value = OriginTrackedValue.of(dataFormatter.formatCellValue(cell), origin);

                    properties.put(key, value);
                }
            }
        }
        return singletonList(new OriginTrackedMapPropertySource(name, unmodifiableMap(properties), true));
    }

    private List<String> rowToList(Row row, DataFormatter dataFormatter) {
        return StreamSupport.stream(row.spliterator(), false).map(dataFormatter::formatCellValue).collect(Collectors.toList());
    }

    private String getPrefix(Resource resource) {
        String fileName = requireNonNull(resource.getFilename());
        String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1);
        if (fileName.startsWith("application-")) {
            fileName = fileName.substring(fileName.indexOf("application-") + 12);
            fileName = fileName.substring(0, fileName.lastIndexOf("."));
        } else {
            fileName = fileName.substring(0, fileName.lastIndexOf("-"));
        }
        return fileExtension + "." + fileName;
    }
}
